﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Broker.SimpleLib
{
    public enum TableType { Data = 0, Score = 1 }

    public class ServerDataTableInfo
    {
        public virtual int Id { get; set; }

        public virtual string Name { get; set; }

        public virtual TableType TableType { get; set; }

        public virtual string SQL { get; set; }

        public virtual bool IsNeedUpdate { get; set; }

        public virtual bool IsIdentity { get; set; }

        public virtual long LastTimeStamp { get; set; }

        public virtual string Description { get; set; }

        public virtual DBTableData TableData { get; set; }


        public virtual void SetServerTableData(DBTableData data)
        {
            TableData.ClientMaxId = data.ClientMaxId;
            TableData.ClientMinId = data.ClientMinId;
            TableData.ClientRowCount = data.ClientRowCount;
            TableData.ClientTs = data.ClientTs;
            TableData.Data = data.Data;
            TableData.Description = data.Description;
            TableData.IsExistDeletedRows = data.IsExistDeletedRows;
            TableData.IsSuccess = data.IsSuccess;
            TableData.Name = data.Name;
            TableData.NoExistId = data.NoExistId;
            TableData.Ids = data.Ids;
            TableData.ServerMaxId = data.ServerMaxId;
            TableData.ServerMinId = data.ServerMinId;
            TableData.ServerNewRowCount = data.ServerNewRowCount;
            TableData.ServerRowCount = data.ServerRowCount;
            TableData.ServerTs = data.ServerTs;

        }

        public virtual long LoadLastTimeStamp(ISession sess)
        {
            long? ts = sess.CreateSQLQuery("select cast(max(ts) as bigint) from " + Name).UniqueResult<long>();

            return ts == null ? 0 : (long)ts;
        }

        public virtual DBTableData LoadData(long clientMinRow, long clientMaxRow, long clientRowCount, long clientTs, string sqlWhere, ISession sess)
        {
            DBTableData ta = GetDBTableDataBaseInfo(clientMinRow, clientMaxRow, clientRowCount, clientTs, sqlWhere, sess);

            //Debug.Assert(Name != "Product_FixRateRecord");
            string sql = null;

            if (ta.ClientTs != ta.ServerTs)//有修改或新增的数据需要下载
            {

                sql = string.Format("select * from ({0}) as x where ts> cast({1} as timestamp) and ts<= cast({2} as timestamp) ", SQL + sqlWhere, clientTs, ta.ServerTs);

                //sql = "select * from " + Name + " where ts> " + clientTs + " and ts<= cast(" + ta.ServerTs + " as timestamp)";

                DataSet ds = new DataSet(Name);
                IDataAdapter da = new SqlDataAdapter(sql, (SqlConnection)sess.Connection);

                da.Fill(ds);

                StringBuilder content = new StringBuilder();
                StringWriter writer = new StringWriter(content);
                XmlTextWriter xmlWriter = new XmlTextWriter(writer);

                ds.WriteXml(xmlWriter, XmlWriteMode.WriteSchema);

                string s = content.ToString();
                byte[] data = TransportUtil.CompressText(s);
                ta.Data = data;

                content.Clear();
                ds.Clear();

                ds.Dispose();



            }
            //判断是否存在需要删除的数据
            if (IsExistDeletedRows(ta, sess))
            {
                //获取当前表的所有id
                sql = "select id from " + Name;

                int[] ids = sess.CreateSQLQuery(sql).List<int>().ToArray();

                ta.Ids = ids;
            }
            return ta;
        }
        /// <summary>
        /// 获取表数据的基本信息
        /// </summary>
        /// <param name="clientMinRow"></param>
        /// <param name="clientMaxRow"></param>
        /// <param name="clientRowCount"></param>
        /// <param name="clientTs"></param>
        /// <param name="sess"></param>
        /// <returns></returns>
        private ServerTableData GetDBTableDataBaseInfo(long clientMinRow, long clientMaxRow, long clientRowCount, long clientTs, string sqlWhere, ISession sess)
        {
            ServerTableData ta = new ServerTableData();
            ta.Name = this.Name;
            ta.ClientMinId = clientMinRow;
            ta.ClientMaxId = clientMaxRow;
            ta.ClientRowCount = clientRowCount;
            ta.ClientTs = clientTs;

            string sql = "select LastTimeStamp from System_TableUpdate where Name='" + Name + "'";

            IList<long?> q = sess.CreateSQLQuery(sql).List<long?>();

            if (q.Count == 0)
            {
                ta.IsSuccess = false;
                ta.Description = "服务器端不支持该表数据的下载!";
            }
            else
            {

                if (Name == "Score_ScoreRecord")
                    ta.ServerTs = sess.CreateSQLQuery("select cast(isnull(max(ts),0) as bigint) from (" + SQL + sqlWhere + ") as x").UniqueResult<long>();
                else
                    ta.ServerTs = q[0] == null ? 0 : (long)q[0];
            }

            sql = "select count(*) as c,min(id) as minId,max(id) as maxId from (" + SQL + sqlWhere + ")as x where Ts<=cast(" + ta.ServerTs + " as timestamp)";

            object[] r = sess.CreateSQLQuery(sql).AddScalar("c", NHibernateUtil.Int64).AddScalar("minId", NHibernateUtil.Int64).AddScalar("maxId", NHibernateUtil.Int64).List<object[]>()[0];
            ta.ServerRowCount = (long)r[0];
            ta.ServerMinId = r[1] == null ? 0 : (long)r[1];
            ta.ServerMaxId = r[2] == null ? 0 : (long)r[2];

            sql = "select count(*) as c from (" + SQL + sqlWhere + ")as x where id>" + ta.ClientMaxId + " and ts>cast(" + ta.ClientTs + " as timestamp) and ts<=cast(" + ta.ServerTs + " as timestamp)";
            ta.ServerNewRowCount = sess.CreateSQLQuery(sql).AddScalar("c", NHibernateUtil.Int64).List<long>()[0];

            return ta;
        }

        private bool IsExistDeletedRows(DBTableData ta, ISession sess)
        {

            //客户端与服务器端行数相同，并且时间戳也相同，表示没有需要删除的行
            if (ta.ServerTs == ta.ClientTs && ta.ServerRowCount == ta.ClientRowCount)
                ta.IsExistDeletedRows = false;
            //服务器端增加的行数等于来服务器、客户端端之差
            else if (ta.ServerRowCount - ta.ClientRowCount == ta.ServerNewRowCount)
                ta.IsExistDeletedRows = false;
            else
                ta.IsExistDeletedRows = true;
            return ta.IsExistDeletedRows;
        }
    }
}
